package com.smy.baseutil.lock;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.smy.baseutil.redis.RedisManager;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisConnectionException;

/**
 * 
* @Title: RedisLock.java  
* @Description: redis锁 
* @author zhoutao    
* @date 2018年1月23日 下午3:48:44  
* @version V1.0
 */
public class RedisLock {


	private static Logger logger = LoggerFactory.getLogger(RedisLock.class);

	private static final String LOCK_KEY = "config.lock";
	//超时时间 秒
	private static final int EXPIRED_TIME = 5;

	/**
	 * 锁在给定的等待时间内空闲，则获取锁成功 返回true， 否则返回false
	 * 
	 * @param subKey
	 * @param timeout
	 *            如果timeout=0,取不到锁时,不等待,直接返回.
	 * @param unit
	 * @return
	 */
	public static boolean tryLock(String subKey, long timeout, TimeUnit unit) {
		String key = LOCK_KEY + subKey;
		Jedis jedis = null;
		try {
			jedis = RedisManager.getJedisPool().getResource();
			if (jedis == null) {
				return Boolean.FALSE;
			}
			long nano = System.nanoTime();
			do {
				Long i = jedis.setnx(key, key);
				if (i == 1) {
					jedis.expire(key, EXPIRED_TIME);
					return Boolean.TRUE;
				} else { // 存在锁
					if (logger.isDebugEnabled()) {
						String desc = jedis.get(key);
						logger.debug("key: " + key + " locked by another business：" + desc);
					}
				}
				if (timeout == 0) { // 取不到锁时,不等待,直接返回.
					break;
				}
				Thread.sleep(200);
			} while ((System.nanoTime() - nano) < unit.toNanos(timeout));// 取不到锁时等待,直到timeout
			return Boolean.FALSE;
		} catch (JedisConnectionException je) {
			logger.error(je.getMessage()+ je);
		} catch (Exception e) {
			logger.error(e.getMessage()+ e);
		} finally {
			if (null != jedis) {
				jedis.close();
			}
		}
		return Boolean.FALSE;
	}

	/**
	 * 如果锁空闲立即返回 获取失败 一直等待
	 * 
	 * @param subKey
	 */
	public static boolean lock(String subKey) {
		String key = LOCK_KEY + subKey;
		Jedis jedis = null;
		boolean isLock = false;
		try {
			jedis = RedisManager.getJedisPool().getResource();
			if (jedis == null) {
				return isLock;
			}
			while (true) {
				logger.debug("lock key: " + key);
				Long i = jedis.setnx(key, key);
				if (i == 1) {
					jedis.expire(key, EXPIRED_TIME);
					logger.debug("get lock, key: " + key + " , expire in " + EXPIRED_TIME + " seconds.");
					isLock = true;
				} else {
					if (logger.isDebugEnabled()) {
						String desc = jedis.get(key);
						logger.debug("key: " + key + " locked by another business：" + desc);
					}
					isLock = false;
				}
				Thread.sleep(500);
			}
		} catch (JedisConnectionException je) {
			logger.error(je.getMessage()+je);
		} catch (Exception e) {
			logger.error(e.getMessage()+e);
		} finally {
			if (null != jedis) {
				jedis.close();
			}
		}
		return isLock;
	}

	/**
	 * 释放锁
	 * 
	 * @param subKey
	 */
	public static void unLock(String subKey) {
		String key = LOCK_KEY + subKey;
		Jedis jedis = null;
		try {
			jedis = RedisManager.getJedisPool().getResource();
			if (jedis == null) {
				return;
			}
			jedis.del(key);
			logger.debug("release lock, keys :" + key);
		} catch (JedisConnectionException je) {
			logger.error(je.getMessage()+ je);
		} catch (Exception e) {
			logger.error(e.getMessage()+ e);
		} finally {
			if (null != jedis) {
				jedis.close();
			}
		}
	}
	


}
